package com.rbac.modules.auth.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.secure.SaSecureUtil;
import com.rbac.modules.auth.dto.LoginDTO;
import com.rbac.modules.auth.dto.LoginVO;
import com.rbac.modules.auth.service.AuthService;
import com.rbac.modules.system.entity.SysUser;
import com.rbac.modules.system.service.SysRoleService;
import com.rbac.modules.system.service.SysPermissionService;
import com.rbac.modules.system.service.SysUserService;
import com.rbac.modules.system.service.SysLoginLogService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import eu.bitwalker.useragentutils.UserAgent;

import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {
    private final SysUserService userService;
    private final SysRoleService roleService;
    private final SysPermissionService permissionService;
    private final SysLoginLogService loginLogService;

    @Override
    public LoginVO login(LoginDTO loginDTO) {
        // 获取请求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String ip = getIpAddress(request);
        String userAgent = request.getHeader("User-Agent");
        UserAgent agent = UserAgent.parseUserAgentString(userAgent);
        String browser = agent.getBrowser().getName();
        String os = agent.getOperatingSystem().getName();

        try {
            // 查询用户
            SysUser user = userService.lambdaQuery()
                    .eq(SysUser::getUsername, loginDTO.getUsername())
                    .one();
            if (user == null) {
                // 记录登录失败日志
                loginLogService.recordLoginLog(loginDTO.getUsername(), ip, null, browser, os, 0, "用户名或密码错误");
                throw new RuntimeException("用户名或密码错误");
            }

            // 验证密码
            if (!SaSecureUtil.md5(loginDTO.getPassword()).equals(user.getPassword())) {
                // 记录登录失败日志
                loginLogService.recordLoginLog(loginDTO.getUsername(), ip, null, browser, os, 0, "用户名或密码错误");
                throw new RuntimeException("用户名或密码错误");
            }

            // 检查用户状态
            if (user.getStatus() == 0) {
                // 记录登录失败日志
                loginLogService.recordLoginLog(loginDTO.getUsername(), ip, null, browser, os, 0, "账号已被禁用");
                throw new RuntimeException("账号已被禁用");
            }

            // 登录
            StpUtil.login(user.getId());

            // 加载用户角色
            List<String> roles = roleService.getRoleCodesByUserId(user.getId());
            // 将角色列表存储到Redis
            StpUtil.getSession().set("roles", roles);

            // 加载用户权限
            List<String> permissions = permissionService.getPermissionCodesByUserId(user.getId());
            // 将权限列表存储到Redis
            StpUtil.getSession().set("permissions", permissions);

            // 将权限列表添加到Sa-Token的权限列表中
            for (String permission : permissions) {
                StpUtil.getPermissionList().add(permission);
            }

            // 将角色列表添加到Sa-Token的角色列表中
            for (String role : roles) {
                StpUtil.getRoleList().add(role);
            }

            // 设置权限和角色到Sa-Token
            StpUtil.getSession().set("permissionList", permissions);
            StpUtil.getSession().set("roleList", roles);

            // 记录登录成功日志
            loginLogService.recordLoginLog(user.getUsername(), ip, null, browser, os, 1, "登录成功");

            log.info("用户登录成功，ID: {}, 用户名: {}, 角色: {}, 权限: {}",
                user.getId(), user.getUsername(), roles, permissions);

            // 返回登录信息
            return new LoginVO()
                    .setUserId(user.getId())
                    .setUsername(user.getUsername())
                    .setRealName(user.getRealName())
                    .setToken(StpUtil.getTokenValue())
                    .setExpireTime(StpUtil.getTokenTimeout());
        } catch (Exception e) {
            // 记录登录失败日志
            loginLogService.recordLoginLog(loginDTO.getUsername(), ip, null, browser, os, 0, e.getMessage());
            throw e;
        }
    }

    @Override
    public void logout() {
        StpUtil.logout();
    }

    @Override
    public Long getLoginUserId() {
        return StpUtil.getLoginIdAsLong();
    }

    @Override
    public String getLoginUsername() {
        Long userId = getLoginUserId();
        SysUser user = userService.getById(userId);
        return user != null ? user.getUsername() : null;
    }

    /**
     * 获取IP地址
     */
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
